﻿using WCS.Repository.Interface;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;

namespace WCS.Repository.Instance
{
    public class SqlRepository<T> : IRepository<T> where T : class, new()
    {
        private readonly DbContext _dbContext;

        public SqlRepository(DbContext dbContext)
        {
            _dbContext = dbContext;
        }
        public Task AddAsync(T t, CancellationToken cancellationToken = default)
            => _dbContext.Set<T>().AddAsync(t, cancellationToken).AsTask();

        public Task AddRangeAsync(IEnumerable<T> ie, CancellationToken cancellationToken = default)
            => _dbContext.Set<T>().AddRangeAsync(ie, cancellationToken);

        public Task DeleteAsync(T t, CancellationToken cancellationToken = default)
        {
            _dbContext.Set<T>().Remove(t);
            return Task.CompletedTask;
        }

        public Task DeleteRangeAsync(IEnumerable<T> ie, CancellationToken cancellationToken = default)
        {
            _dbContext.Set<T>().RemoveRange(ie);
            return Task.CompletedTask;
        }

        public Task UpdateAsync(T t, CancellationToken cancellationToken = default)
        {
            _dbContext.Entry(t).State = EntityState.Modified;
            return Task.CompletedTask;
        }

        public Task UpdateRangeAsync(IEnumerable<T> ie, CancellationToken cancellationToken = default)
        {
            foreach (var item in ie)
                _dbContext.Entry(item).State = EntityState.Modified;

            return Task.CompletedTask;
        }

        public Task<T?> FindAsync(params object?[]? values)
            => _dbContext.Set<T>().FindAsync(values).AsTask();

        public Task<T?> FindAsync(object?[]? values, CancellationToken cancellationToken = default)
            => _dbContext.Set<T>().FindAsync(values, cancellationToken).AsTask();

        public Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
            => _dbContext.SaveChangesAsync(cancellationToken);


        public IQueryable<T> QueryAll(Expression<Func<T, bool>>? where)
        {
            var iq = (IQueryable<T>)_dbContext.Set<T>();
            if (where != null)
            {
                iq = iq.Where(where);
            }
            return iq;
        }

        public IQueryable<T> QueryAll<type>(Expression<Func<T, bool>>? where, Expression<Func<T, type>>? order, bool isAsc = true)
        {
            var iq = this.QueryAll(where);
            if (isAsc)
            {
                return iq.OrderBy(order);
            }
            else
            {
                return iq.OrderByDescending(order);
            }
        }

        public IQueryable<T> QueryAll<type>(out int total, int skip, int take, Expression<Func<T, bool>>? where, Expression<Func<T, type>>? order, bool isAsc = true)
        {
            var iq = this.QueryAll(where, order, isAsc);
            total = iq.Count();
            return iq.Skip(skip).Take(take);
        }
    }
}
